package aceim.protocol.snuk182.icq.inner.dataprocessing;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import aceim.protocol.snuk182.icq.inner.ICQConstants;
import aceim.protocol.snuk182.icq.inner.ICQException;
import aceim.protocol.snuk182.icq.inner.ICQServiceInternal;
import aceim.protocol.snuk182.icq.inner.dataentity.ICQBuddy;
import aceim.protocol.snuk182.icq.inner.dataentity.ICQDCInfo;
import aceim.protocol.snuk182.icq.inner.dataentity.ICQIconData;
import aceim.protocol.snuk182.icq.inner.dataentity.ICQOnlineInfo;
import aceim.protocol.snuk182.icq.inner.dataentity.Snac;
import aceim.protocol.snuk182.icq.inner.dataentity.TLV;
import aceim.protocol.snuk182.icq.utils.ProtocolUtils;
public class OnlineInfoEngine {
private ICQServiceInternal service;
public OnlineInfoEngine(ICQServiceInternal icqServiceInternal){
this.service = icqServiceInternal;
}
public List<ICQOnlineInfo> parseOnlineInfo(Snac snac, ICQOnlineInfo info) throws ICQException{
service.log(" online info:");
if (snac.plainData == null || snac.plainData.length<1) {
return null;
}
List<ICQOnlineInfo> infos = new ArrayList<ICQOnlineInfo>();
int pos =0;
/*if (snac.plainData[pos]!=service.getUn().length()){
pos+=8;
}*/
while (pos<snac.plainData.length){
ICQOnlineInfo nfo;
if (info != null && pos==0){
nfo = info;
} else {
nfo = new ICQOnlineInfo();
}
if (snac.plainData[pos] == 0){
pos+=ProtocolUtils.bytes2ShortBE(snac.plainData, pos)+2;
}
int ln = snac.plainData[pos];
pos++;
String uin;
try {
uin = new String(snac.plainData, pos, ln, "ASCII");
} catch (UnsupportedEncodingException e) {
uin = new String(snac.plainData, pos, ln);
}
nfo.uin = uin;
service.log(" uin: "+uin);
pos+= ln;
short warnLevel = ProtocolUtils.bytes2ShortBE(snac.plainData, pos);
nfo.warnLevel = warnLevel;
service.log(" warn level: "+warnLevel);
pos+=2;
int tlvCount = ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortBE(snac.plainData, pos));
pos+=2;
for (int i=0; i<tlvCount; i++){
try {
TLV tlv = new TLV();
tlv.type = (snac.plainData[pos]<<8)+snac.plainData[++pos];
int length = ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortBE(snac.plainData, ++pos));
++pos;
//service.log(" tlv length="+length);
if (length>0 && snac.plainData.length>4){
byte[] tailData = new byte[length];
System.arraycopy(snac.plainData, ++pos, tailData, 0, length);
tlv.value = tailData;
pos+=length;
} else {
++pos;
}
onlineInfoTLVMap(tlv, nfo);
} catch (Exception e) {
service.log(e);
throw new ICQException(e.getMessage());
}
}
if (!uin.equals(service.getUn())){
nfo.visibility = service.getBuddyList().denyList.get(uin) !=null ? ICQConstants.VIS_DENIED : (service.getBuddyList().permitList.get(uin) !=null ? ICQConstants.VIS_PERMITTED : ICQConstants.VIS_REGULAR);
/*if (nfo.userStatus != ICQConstants.STATUS_OFFLINE){
service.getBuddyList().removeFromNotAuthListByUin(uin);
}*/
for (ICQBuddy buddy : service.getBuddyList().notAuthList) {
if (buddy.uin.equals(uin)) {
nfo.visibility = ICQConstants.VIS_NOT_AUTHORIZED;
break;
}
}
}
infos.add(nfo);
}
return infos;
}
ICQOnlineInfo onlineInfoTLVMap(TLV tlv, ICQOnlineInfo info) throws ICQException{
if (tlv == null){
return info;
}
ICQOnlineInfo internalInfo;
if (info == null){
internalInfo = new ICQOnlineInfo();
} else {
internalInfo = info;
}
switch (tlv.type){
case ICQConstants.TLV_ONLINE_USERCLASS:
internalInfo.userClass = ProtocolUtils.bytes2ShortBE(tlv.value);
service.log(" user class: "+internalInfo.userClass);
break;
case ICQConstants.TLV_ONLINE_ACCOUNTCREATIONTIME:
internalInfo.memberSinceTime = ProtocolUtils.bytes2Date(tlv.value);
service.log(" member since: "+internalInfo.memberSinceTime);
break;
case ICQConstants.TLV_ONLINE_CREATETIME:
internalInfo.createTime = ProtocolUtils.bytes2Date(tlv.value);
service.log(" create time: "+internalInfo.createTime);
break;
case ICQConstants.TLV_ONLINE_IDLETIME:
internalInfo.idleTime = ProtocolUtils.bytes2IntBE(tlv.value);
service.log(" idle: "+internalInfo.idleTime);
break;
case ICQConstants.TLV_ONLINE_SIGNONTIME:
internalInfo.signonTime = ProtocolUtils.bytes2Date(tlv.value);
service.log(" signon: "+internalInfo.signonTime);
break;
case ICQConstants.TLV_ONLINE_USERSTATUS:
int userStatus = ProtocolUtils.bytes2IntBE(tlv.value);
service.log(" status: "+ProtocolUtils.getSpacedHexString(tlv.value));
if (service.getOnlineInfo() != internalInfo) {
internalInfo.userStatus = userStatus;
}
break;
case ICQConstants.TLV_ONLINE_OWNNAME:
internalInfo.name = ProtocolUtils.getEncodedString(tlv.value);
service.log(" name: "+internalInfo.name);
//service.getServiceResponse().respond(IProtocolServiceResponse.RES_OWNINFO, service.getServiceId(), args);
break;
case ICQConstants.TLV_ONLINE_DCINFO:
try {
internalInfo.dcInfo = parseDCInfo(tlv.value);
service.log(" dc info: "+internalInfo.dcInfo.internalIP);
} catch (ICQException e) {
//to do
}
break;
case ICQConstants.TLV_ONLINE_CAPABILITIES:
internalInfo.capabilities = parseCapabilities(tlv.value);
service.log(" capabilities: "+internalInfo.capabilities.size());
break;
case ICQConstants.TLV_ONLINE_EXTERNALIP:
try {
internalInfo.extIP = ProtocolUtils.unsignedByte2Short(tlv.value[0])+"."+ProtocolUtils.unsignedByte2Short(tlv.value[1])+"."+ProtocolUtils.unsignedByte2Short(tlv.value[2])+"."+ProtocolUtils.unsignedByte2Short(tlv.value[3]);
} catch (Exception e) {
internalInfo.extIP = "";
}
service.log(" external ip: "+internalInfo.extIP);
break;
case ICQConstants.TLV_ONLINE_ONLINETIME:
internalInfo.onlineTime = ProtocolUtils.bytes2IntBE(tlv.value);
service.log(" online since: "+internalInfo.onlineTime);
break;
case ICQConstants.TLV_DISTRIBUTIONNUMBER:
internalInfo.distribNumber = tlv.value[0];
service.log(" distribution: "+internalInfo.distribNumber);
break;
case ICQConstants.TLV_ONLINE_ICONDATA:
ICQIconData[] data = parseIconData(tlv.value);
if (data !=null){
for (ICQIconData item:data){
if (item != null){
switch(item.iconId){
case 0x1:
if (internalInfo.iconData != null && internalInfo.iconData.ssiItemId != 0) {
item.ssiItemId = internalInfo.iconData.ssiItemId;
}
internalInfo.iconData = item;
service.log(" icon id "+ProtocolUtils.getHexString(item.hash) + " flags "+item.flags);
break;
case 0x2:
if (item.hash.length>3 && internalInfo.uin!=null && !internalInfo.uin.equals(service.getUn())){
int textLength = ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortBE(item.hash, 0));
try {
internalInfo.personalText = new String(item.hash, 2, textLength, "UTF-8");
} catch (UnsupportedEncodingException e) {
internalInfo.personalText = new String(item.hash, 2, textLength);
}
}
service.log(" extra text "+internalInfo.personalText);
break;
case 0xd:
/*if (internalInfo.iconData==null){
internalInfo.iconData = item;
}*/
service.log(" HEX "+ProtocolUtils.getHexString(item.hash));
break;
}
}
}
}
break;
default:
internalInfo.tlvs.add(tlv);
service.log(" unknown tlv: "+ProtocolUtils.getSpacedHexString(ProtocolUtils.int2ByteBE(tlv.type)));
break;
}
return internalInfo;
}
ICQDCInfo parseDCInfo(byte[] in) throws ICQException{
if (in.length<37){
throw new ICQException("Error - not a ICQDCInfo");
}
ICQDCInfo info = new ICQDCInfo();
byte[] buffer = new byte[4];
System.arraycopy(in, 0, buffer, 0, 4);
info.internalIP = ProtocolUtils.getSpacedHexString(buffer).replace(' ', '.');
System.arraycopy(in, 4, buffer, 0, 4);
info.tcpPort = ProtocolUtils.bytes2IntBE(buffer)+"";
info.type = in[8];
System.arraycopy(in, 9, buffer, 0, 2);
info.protocolVersion = ProtocolUtils.bytes2ShortBE(buffer);
System.arraycopy(in, 11, buffer, 0, 4);
info.authCookie = ProtocolUtils.bytes2ShortBE(buffer);
System.arraycopy(in, 15, buffer, 0, 4);
info.webFrontPort = ProtocolUtils.getSpacedHexString(buffer).replace(' ', '.');
System.arraycopy(in, 23, buffer, 0, 4);
info.lastInfoUpdateTime = ProtocolUtils.bytes2Date(buffer);
System.arraycopy(in, 27, buffer, 0, 4);
info.lastExtInfoUpdateTime = ProtocolUtils.bytes2Date(buffer);
System.arraycopy(in, 31, buffer, 0, 4);
info.lastExtStatusUpdateTime = ProtocolUtils.bytes2Date(buffer);
System.arraycopy(in, 35, buffer, 0, 2);
info.smth = ProtocolUtils.bytes2ShortBE(buffer);
return info;
}
ICQIconData[] parseIconData(byte[] value){
if (value==null) return null;
List<ICQIconData> dataList = new ArrayList<ICQIconData>();
int pos = 0;
while(pos<value.length){
ICQIconData iconData = new ICQIconData();
short iconId = ProtocolUtils.bytes2ShortBE(value, pos);
pos +=2;
byte flags = value[pos];
pos++;
byte[] hash = new byte[ProtocolUtils.unsignedByte2Short(value[pos])];
pos++;
System.arraycopy(value, pos, hash, 0, hash.length);
pos+=hash.length;
iconData.iconId = iconId;
iconData.flags = flags;
iconData.hash = hash;
dataList.add(iconData);
}
ICQIconData[] array = new ICQIconData[dataList.size()];
for (int i=0; i<dataList.size(); i++){
array[i] = dataList.get(i);
}
return array;
}
List<String> parseCapabilities(byte[] in){
List<String> caps = new ArrayList<String>();
if (in == null){
return caps;
}
int pos = 0;
while (pos<in.length){
byte[] cap = new byte[16];
System.arraycopy(in, pos, cap, 0, 16);
String strCap = ProtocolUtils.getHexString(cap);
//service.log("cap "+strCap);
caps.add(strCap);
pos+=16;
}
return caps;
}
}